home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 1.iso
/
toolbox
/
src
/
exampleCode
/
opengl
/
extensions
/
samples
/
videowarp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-11
|
15KB
|
560 lines
/*
* Copyright (c) 1994 Silicon Graphics, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that (i) the above copyright notices and this permission
* notice appear in all copies of the software and related documentation,
* and (ii) the name of Silicon Graphics may not be used in any
* advertising or publicity relating to the software without the specific,
* prior written permission of Silicon Graphics.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
* INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/*
* videowarp.c
*
* Demonstrate video-to-texture transfers from Sirius in OpenGL.
*
* The video image is warpped as if it is on a rubber sheet whose sides are
* pinned down but the center is being twisted back a forth.
*
* See the usage() function for the command line options (or run with -h).
*
* Keys: w - toggle warping on/off
*
* Algorithm:
* The video frames are copied to texture memory
* The texture is mapped onto a spline mesh that for which the control point
* are rotated back and forth thus resulting in a warping effect.
*
* $Revision: 1.1 $
*/
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <X11/keysym.h>
#include <device.h>
#include <vl/vl.h>
#include <vl/dev_sirius.h>
#include <GL/glx.h>
#include <GL/glu.h>
#include "xwindow.h"
GLenum internalTextureFormat;
static float texture_matrix[4][4] = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
/*
* VL defines
*/
VLControlValue size, timing;
VLControlValue format;
VLControlValue cap_type;
VLServer svr;
VLPath path;
VLNode src;
VLNode drn;
/* OpenGL/X variables */
Display *dpy;
Window window;
#ifdef GLX_SGIX_video_source
GLXVideoSourceSGIX glxVideoSource;
#else /* Make the compiler barf */
GLX_SGIX_video_source is not defined in this version of the library
#endif
/* parameters of the evaluator map for vertexes */
#define S_ORDER 4
#define T_ORDER 4
#define S_SEGMENTS 10
#define T_SEGMENTS 10
#define S_MAPS 2
#define T_MAPS 2
#define DELTA_ROT 10
float rotang = DELTA_ROT;
float totang = 0;
int s_points, t_points;
int s_stride, t_stride;
/*
* function prototypes
*/
void usage(char *, int);
void initVideo(int, int, int);
void initGfx(int argc, char *argv[], int packingFormat);
void initWarp(void);
void initVertCoords(void);
void cleanup(void);
void displayFrame(void);
void processEvents(void);
void updateVideoFormat(void);
int
main(int argc, char **argv)
{
int c, insrc = VL_ANY;
int device = VL_ANY;
short dev, val;
int packingFormat = 5;
/* Parse the input string */
while ((c = getopt(argc, argv, "n:t:v:hwFgpm")) != EOF ) {
switch (c) {
case 'n':
device = atoi(optarg); /* user can override default device */
break;
case 't':
packingFormat = atoi(optarg);
break;
case 'v':
insrc = atoi(optarg);
break;
case 'h':
usage(argv[0], EXIT_SUCCESS);
default:
usage(argv[0], EXIT_FAILURE);
}
}
initVideo(insrc, device, packingFormat);
updateVideoFormat();
initGfx(argc, argv, packingFormat);
vlBeginTransfer(svr, path, 0, NULL);
while (TRUE) {
if (XEventsQueued(dpy, QueuedAfterReading)) {
XEvent event;
XNextEvent(dpy, &event);
switch (event.type) {
case KeyPress: {
KeySym key;
(void) XLookupString(&event.xkey, NULL, 0, &key, NULL);
switch (key) {
case XK_Escape:
exit(EXIT_FAILURE);
break;
case XK_w:
rotang = rotang == 0 ? DELTA_ROT : 0;
break;
case XK_i:
totang = 0;
initVertCoords();
break;
case XK_h:
case XK_H:
case XK_question:
printf("Keys:\tw - toggle warpping on/off\n");
printf("\th/? - help\n");
printf("\tEsc - quit\n");
break;
}
}
}
}
/* Check for VL events if any ... */
processEvents();
/* Next frame of data */
displayFrame();
glXSwapBuffers(dpy, window);
}
}
void
initVideo(int insrc, int device, int packingFormat)
{
VLControlValue texctl;
/* open the server */
if (!(svr = vlOpenVideo(""))) {
printf("couldn't open video\n");
exit(EXIT_FAILURE);
}
/* Get the Video source */
src = vlGetNode(svr, VL_SRC, VL_VIDEO, insrc);
/* Get the Texture drain */
drn = vlGetNode(svr, VL_DRN, VL_TEXTURE, 0);
/* Create path */
path = vlCreatePath(svr, device, src, drn);
if (path < 0) {
vlPerror("vlCreatePath");
exit(EXIT_FAILURE);
}
/* setup path */
if (vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE, VL_SHARE) < 0) {
vlPerror("vlSetupPaths");
exit(EXIT_FAILURE);
}
/* select the appropriate events */
if (vlSelectEvents(svr, path, VLStreamPreemptedMask |
VLControlChangedMask ) < 0) {
vlPerror("Select Events");
exit(EXIT_FAILURE);
}
cap_type.intVal = VL_CAPTURE_INTERLEAVED;
if (vlSetControl(svr, path, drn, VL_CAP_TYPE, &cap_type) <0) {
vlPerror("VlSetControl");
exit(EXIT_FAILURE);
}
switch(packingFormat) {
case 4:
texctl.intVal = SIR_TEX_PACK_RGBA_4;
break;
case 8:
texctl.intVal = SIR_TEX_PACK_RGBA_8;
break;
case 5:
default:
texctl.intVal = SIR_TEX_PACK_RGB_5;
break;
}
/* Set the Texture packing mode */
if (vlSetControl(svr, path, drn, VL_PACKING, &texctl) <0) {
vlPerror("VlSetControl");
exit(EXIT_FAILURE);
}
updateVideoFormat();
}
void
usage(char *name, int exitStatus)
{
fprintf(stderr, "usage: %s [-n#] [-v#] [-t#] [-h (for help)]\n", name);
fprintf(stderr, "\t-n# video device number (as reported by vlinfo)\n");
fprintf(stderr, "\t-v# video input number (as reported by vlinfo)\n");
fprintf(stderr, "\t-t# texture format (as packed by Sirius)\n");
fprintf(stderr,
"\tInteractively, `h/?' keys provide description of interface\n");
exit(exitStatus);
}
/*
* CreateTexture: Create a texture map with correct attributes.
*/
int t_width, t_height;
void
initGfx(int argc, char *argv[], int packingFormat)
{
GLubyte fakeTexture[1024][1024][3];
float s_scale, t_scale;
GLXContext ctx;
int visualAttr[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1,
GLX_DEPTH_SIZE, 0, GLX_STENCIL_SIZE, 0,
None};
createWindowAndContext(&dpy, &window, &ctx,
100, 100, 100 + size.xyVal.x, 100 + size.xyVal.y,
GL_FALSE, NULL, visualAttr, argv[0]);
glxVideoSource = glXCreateGLXVideoSourceSGIX(dpy, DefaultScreen(dpy), svr,
path, VL_TEXTURE, drn);
if (glxVideoSource == None) {
fprintf(stderr, "can't create video source\n");
exit(EXIT_FAILURE);
}
if (!glXMakeCurrentReadSGI(dpy, window, glxVideoSource, ctx)) {
fprintf(stderr, "Can't make current to video\n");
exit(EXIT_FAILURE);
}
/*
* Set up texture parameters.
*/
/* Match internal format to external packing format */
switch(packingFormat) {
case 4:
internalTextureFormat = GL_RGBA4_EXT;
printf ("using RGBA4\n");
break;
case 8:
internalTextureFormat = GL_RGBA8_EXT;
printf ("using RGBA8\n");
break;
case 5:
default:
internalTextureFormat = GL_RGB5_EXT;
printf ("using RGB5\n");
break;
}
/*
* 625 textures are bigger than 525 textures
*/
if ((timing.intVal == VL_TIMING_525_SQ_PIX) ||
(timing.intVal == VL_TIMING_525_CCIR601)) {
t_width = 1024;
t_height = 512;
} else {
t_width = 1024;
t_height = 1024;
}
s_scale = (size.xyVal.x - 1) / (float)t_width;
t_scale = size.xyVal.y / (float)t_height;
texture_matrix[0][0] = s_scale;
texture_matrix[1][1] = -t_scale;
texture_matrix[3][1] = t_scale;
initWarp();
glEnable(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, internalTextureFormat, t_width, t_height,
0, GL_RGB, GL_UNSIGNED_BYTE, fakeTexture);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf((GLfloat *) texture_matrix);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1, 1, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0., 0., - 7);
glTranslatef(-(s_points - 1)/2.0, -(t_points - 1)/2.0, 0);
/* Setup tranfromation matrices */
glMapGrid2f(S_SEGMENTS, 0, 1, T_SEGMENTS, 0, 1);
glEnable(GL_MAP2_TEXTURE_COORD_2);
glEnable(GL_MAP2_VERTEX_3);
}
void
cleanup()
{
vlEndTransfer(svr, path);
vlDestroyPath(svr, path);
vlCloseVideo(svr);
exit(EXIT_SUCCESS);
}
void
processEvents()
{
VLEvent ev;
/* Check to see if any controls changed or if the video
* path has been pre-empted.
*/
if (vlCheckEvent(svr, VLControlChangedMask|
VLStreamPreemptedMask, &ev) == -1) {
return;
}
switch(ev.reason) {
case VLStreamPreempted:
cleanup();
break;
case VLControlChanged:
switch(ev.vlcontrolchanged.type) {
case VL_TIMING:
case VL_SIZE:
case VL_PACKING:
updateVideoFormat();
printf("got timing, size, or packing event\n");
break;
default:
break;
}
break;
default:
break;
}
}
void
updateVideoFormat()
{
/* Get the timing from input source */
if (vlGetControl(svr, path, src, VL_TIMING, &timing) < 0) {
vlPerror("vlGetControl");
exit(EXIT_FAILURE);
}
/* Set texture drain's timing to input source */
if (vlSetControl(svr, path, drn, VL_TIMING, &timing) < 0) {
vlPerror("vlSetControl");
exit(EXIT_FAILURE);
}
if (vlGetControl(svr, path, src, VL_SIZE, &size) < 0) {
vlPerror("vlSetupPaths");
exit(EXIT_FAILURE);
}
printf("control size: %3d x %3d\n", size.xyVal.x, size.xyVal.y);
}
/**************************************************************************/
/*
* Routines to warp the video.
*/
/* parameters of the evaluator map for texture coords */
int tx_s_stride, tx_t_stride;
int tx_s_points, tx_t_points;
int tx_ncomp = 2;
float limitang = 220;
GLfloat *textureMap = NULL, *vertexMap = NULL;
/*
* Initialize the evaluators used for the warping.
*/
void
initWarp(void)
{
int s, t;
GLfloat *p;
/* the vertex coord map starts out regularly spaced; it's warped later */
s_points = S_ORDER + (S_MAPS - 1) * (S_ORDER - 1);
t_points = T_ORDER + (T_MAPS - 1) * (T_ORDER - 1);
s_stride = 3;
t_stride = 3 * s_points;
/* the texture coord map is just a linear, regularly spaced grid */
tx_s_points = S_MAPS + 1;
tx_t_points = T_MAPS + 1;
tx_s_stride = tx_ncomp;
tx_t_stride = tx_ncomp * tx_s_points;
textureMap = malloc(tx_s_points * tx_t_points * tx_ncomp * sizeof(GLfloat));
vertexMap = malloc(s_points * t_points * 3 * sizeof(GLfloat));
initVertCoords();
p = textureMap;
for (t = 0; t < tx_t_points; t++) {
for (s = 0; s < tx_s_points; s++, p += tx_ncomp) {
p[0] = s/(tx_s_points - 1.0);
p[1] = t/(tx_t_points - 1.0);
}
}
}
void
initVertCoords()
{
GLfloat *p;
int s, t;
p = vertexMap;
for (t = 0; t < t_points; t++) {
for (s = 0; s < s_points; s++, p += 3) {
p[0] = s;
p[1] = t;
p[2] = 0;
}
}
}
void
rotate_pts(int level, float ang)
{
int i, s, t;
float *p, v[3], tv[3];
float x, y, z;
float ts, tt;
GLfloat mat[4][4];
/* use the GL to compute our rotation matrix, then read it back */
/* not recommended for programs that care about performance :-) */
glPushMatrix();
glLoadIdentity();
glTranslatef((s_points - 1)/2.0, (t_points - 1)/2.0, 0);
glRotatef(ang, 0, 0, 1);
glTranslatef(-(s_points - 1)/2.0, -(t_points - 1)/2.0, 0);
glGetFloatv(GL_MODELVIEW_MATRIX, &mat[0][0]);
glPopMatrix();
for (t = level; t < t_points - level; t++) {
for (s = level; s < s_points - level; s++) {
if (s > level && s < s_points - level - 1 &&
t > level && t < t_points - level - 1){
continue;
}
p = vertexMap + t * t_stride + s * s_stride;
/* Transform the control point */
tv[0] = p[0] * mat[0][0] + p[1] * mat[1][0] + p[2] * mat[2][0] +
mat[3][0];
tv[1] = p[0] * mat[0][1] + p[1] * mat[1][1] + p[2] * mat[2][1] +
mat[3][1];
tv[2] = p[0] * mat[0][2] + p[1] * mat[1][2] + p[2] * mat[2][2] +
mat[3][2];
p[0] = tv[0];
p[1] = tv[1];
p[2] = tv[2];
}
}
totang += rotang;
if (limitang != 0 && (totang > limitang || totang < -limitang)) {
rotang = -rotang;
}
}
/*
* displayFrame: Display a new texture. This routine is called at 30
* Hz for 525 timing and 25Hz for 625 timing.
*/
void
displayFrame()
{
int is, it;
float *p;
/* Load the texture from Sirius to Texture memory */
glCopyTexSubImage2DEXT(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 768, t_height);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
rotate_pts(1, rotang);
rotate_pts(2, 0.5 * rotang);
for (it = 0; it < T_MAPS; it++) {
for (is = 0; is < S_MAPS; is++) {
p = vertexMap + it * t_stride * (T_ORDER - 1) +
is * s_stride * (S_ORDER - 1);
glMap2f(GL_MAP2_VERTEX_3, 0, 1,
s_stride, 4, 0, 1, t_stride, 4, p);
p = textureMap + it * tx_t_stride + is * tx_s_stride;
glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1,
tx_s_stride, 2, 0, 1, tx_t_stride, 2, p);
glEvalMesh2(GL_FILL, 0, S_SEGMENTS, 0, T_SEGMENTS);
}
}
glDisable(GL_TEXTURE_2D);
}